package gui;

import java.awt.Point;

import image.Layer;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.EventHandler;
import javafx.scene.Cursor;
import javafx.scene.Group;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Polyline;
import javafx.scene.shape.Rectangle;

/**
 * A manager that worries about making helper-tools visible for selected modes
 * 
 * @author Etienne Bruines
 * @author Bas Dobbelsteen
 */
public class ModeManager
{
	private final Settings settings;
	private final ImageManager imageManager;

	public ModeManager(final Settings s, final ImageManager imageManager)
	{
		this.settings = s;
		this.imageManager = imageManager;
		s.modeProperty().addListener(new ChangeListener<Mode>()
		{
			@Override public void changed(ObservableValue<? extends Mode> observable, Mode oldValue, Mode newValue)
			{
				switch (oldValue)
				{
				case Modify:
					removeRectangleAroundShape();
					break;
				}
				switch (newValue)
				{
				case Modify:
					createRectangleAroundShape();
					break;
				}
			}
		});
		imageManager.getActiveImage().activeProperty().addListener(new ChangeListener<Layer>() {
			@Override public void changed(ObservableValue<? extends Layer> observable, Layer oldValue, Layer newValue)
			{
				switch (s.getMode())
				{
				case Modify:
					removeRectangleAroundShape();
					createRectangleAroundShape();
					break;
				}
			}
		});
	}

	private Group aroundGroup;
	
	private void createRectangleAroundShape()
	{
		System.out.println("Rect created");
		final Layer selected = imageManager.getActiveImage().getActiveLayer();
		if (selected == null)
			return;
		
		aroundGroup = new Group();
		
		Rectangle around = new Rectangle(selected.getX(), selected.getY(), selected.getWidth(), selected.getHeight());
		around.xProperty().bind(selected.xProperty());
		around.yProperty().bind(selected.yProperty());
		around.rotateProperty().bind(selected.getContent().rotateProperty());
		around.widthProperty().bind(selected.widthProperty());
		around.heightProperty().bind(selected.heightProperty());
//		around.widthProperty().bind(selected.getContent().scaleXProperty().multiply(selected.getWidth()));
//		around.heightProperty().bind(selected.getContent().scaleYProperty().multiply(selected.getHeight()));

		around.setId("MODIFY");
		around.setFill(Color.TRANSPARENT);
		around.setStroke(Color.LIGHTGRAY);
		around.getStrokeDashArray().addAll(6.0);
		around.setStrokeDashOffset(20);
		around.setStrokeWidth(2);
		
		final int size = 10;
		final Color background = Color.BEIGE;
		final Color stroke = Color.DARKGRAY;
		
		EventHandler<MouseEvent> onRelease = new EventHandler<MouseEvent>() {
			@Override public void handle(MouseEvent event)
			{
				resizeSettings.startPoint = null;
			}
		};
		
		Rectangle topLeft = new Rectangle(selected.getX() - size / 2, selected.getY() - size / 2, size,  size);
		topLeft.xProperty().bind(selected.xProperty().add(-size/2));
		topLeft.yProperty().bind(selected.yProperty().add(-size/2));
		topLeft.setFill(background);
		topLeft.setStroke(stroke);
		topLeft.setCursor(Cursor.NW_RESIZE);
		topLeft.setOnMouseDragged(new EventHandler<MouseEvent> () {
			@Override public void handle(MouseEvent arg0)
			{
				if (resizeSettings.startPoint == null)
				{
					Point p = new Point();
					p.setLocation(arg0.getX(), arg0.getY());
					resizeSettings.startPoint = p;
				}
				else
				{
					double dX = resizeSettings.startPoint.getX() - arg0.getX();
					double dY = resizeSettings.startPoint.getY() - arg0.getY();
					double xScale = 1 + dX / selected.getWidth();
					double yScale = 1 + dY / selected.getHeight();
					System.out.println("Scaling to " + xScale);
					selected.getContent().setScaleX(xScale);
					selected.getContent().setScaleY(yScale);
				}
				arg0.consume();
			}
		});
		topLeft.setOnMouseReleased(onRelease);
		
		Rectangle topRight = new Rectangle(selected.getX() + selected.getWidth() - size / 2, selected.getY() - size / 2, size,  size);
		topRight.xProperty().bind(selected.xProperty().add(around.widthProperty()).add(-size/2));
		topRight.yProperty().bind(selected.yProperty().add(-size/2));
		topRight.setFill(background);
		topRight.setStroke(stroke);
		topRight.setCursor(Cursor.NE_RESIZE);
		topRight.setOnMouseDragged(new EventHandler<MouseEvent> () {
			@Override public void handle(MouseEvent arg0)
			{
				if (resizeSettings.startPoint == null)
				{
					Point p = new Point();
					p.setLocation(arg0.getX(), arg0.getY());
					resizeSettings.startPoint = p;
				}
				else
				{
					double dX = arg0.getX() - resizeSettings.startPoint.getX();
					double dY = resizeSettings.startPoint.getY() - arg0.getY();
					double xScale = 1 + dX / selected.getWidth();
					double yScale = 1 + dY / selected.getHeight();
					System.out.println("Scaling to " + xScale);
					selected.getContent().setScaleX(xScale);
					selected.getContent().setScaleY(yScale);
				}
				arg0.consume();
			}
		});
		topRight.setOnMouseReleased(onRelease);
		
		Polyline topRightRotate = new Polyline(15.0, 0.0, 0.0, 0.0, 15.0, -15.0);
		topRightRotate.layoutXProperty().bind(selected.xProperty().add(around.widthProperty()).add(size/2));
		topRightRotate.layoutYProperty().bind(selected.yProperty().add(-size));
		topRightRotate.setFill(background);
		topRightRotate.setStroke(stroke);
		topRightRotate.setCursor(Cursor.MOVE);
		topRightRotate.setOnMouseDragged(new EventHandler<MouseEvent> () {
			@Override public void handle(MouseEvent arg0)
			{
				if (resizeSettings.startPoint == null)
				{
					Point p = new Point();
					p.setLocation(arg0.getX(), arg0.getY());
					resizeSettings.startPoint = p;
				}
				else
				{
					double dX = resizeSettings.startPoint.getX() - arg0.getX();
					double dY = arg0.getY() - resizeSettings.startPoint.getY();
					double max = (dX + dY) / 5 % 360;
					selected.getContent().setRotate(max);
				}
				arg0.consume();
			}
		});
		topRightRotate.setOnMouseReleased(onRelease);
		
		Rectangle bottomLeft = new Rectangle(selected.getX() - size / 2, selected.getY() + selected.getHeight() - size / 2, size,  size);
		bottomLeft.xProperty().bind(selected.xProperty().add(-size/2));
		bottomLeft.yProperty().bind(selected.yProperty().add(around.heightProperty()).add(-size/2));
		bottomLeft.setFill(background);
		bottomLeft.setStroke(stroke);
		bottomLeft.setCursor(Cursor.SW_RESIZE);
		bottomLeft.setOnMouseDragged(new EventHandler<MouseEvent> () {
			@Override public void handle(MouseEvent arg0)
			{
				if (resizeSettings.startPoint == null)
				{
					Point p = new Point();
					p.setLocation(arg0.getX(), arg0.getY());
					resizeSettings.startPoint = p;
				}
				else
				{
					double dX = resizeSettings.startPoint.getX() - arg0.getX();
					double dY = arg0.getY() - resizeSettings.startPoint.getY();
					double xScale = 1 + dX / selected.getWidth();
					double yScale = 1 + dY / selected.getHeight();
					System.out.println("Scaling to " + xScale);
					selected.getContent().setScaleX(xScale);
					selected.getContent().setScaleY(yScale);
				}
				arg0.consume();
			}
		});
		bottomLeft.setOnMouseReleased(onRelease);
		
		Rectangle bottomRight = new Rectangle(selected.getX() + selected.getWidth() - size / 2, selected.getY() + selected.getHeight() - size / 2, size,  size);
		bottomRight.xProperty().bind(selected.xProperty().add(around.widthProperty()).add(-size/2));
		bottomRight.yProperty().bind(selected.yProperty().add(around.heightProperty()).add(-size/2));
		bottomRight.setFill(background);
		bottomRight.setStroke(stroke);
		bottomRight.setCursor(Cursor.SE_RESIZE);
		bottomRight.setOnMouseDragged(new EventHandler<MouseEvent> () {
			@Override public void handle(MouseEvent arg0)
			{
				if (resizeSettings.startPoint == null)
				{
					Point p = new Point();
					p.setLocation(arg0.getX(), arg0.getY());
					resizeSettings.startPoint = p;
				}
				else
				{
					double dX = arg0.getX() - resizeSettings.startPoint.getX();
					double dY = arg0.getY() - resizeSettings.startPoint.getY();
					double xScale = 1 + dX / selected.getWidth();
					double yScale = 1 + dY / selected.getHeight();
					System.out.println("Scaling to " + xScale);
					selected.getContent().setScaleX(xScale);
					selected.getContent().setScaleY(yScale);
				}
				arg0.consume();
			}
		});
		bottomRight.setOnMouseReleased(onRelease);
		
		aroundGroup.getChildren().addAll(around, topLeft, topRight, topRightRotate, bottomLeft, bottomRight);
		imageManager.getActiveImage().getGroup().getChildren().add(aroundGroup);
	}
	
	private static class resizeSettings
	{
		public static Point startPoint;
	}
	
	private void removeRectangleAroundShape()
	{
		if (aroundGroup != null)
		{
			imageManager.getActiveImage().getGroup().getChildren().remove(aroundGroup);
			aroundGroup = null;
		}
	}
}
